package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.User;
import com.hmdp.mapper.UserMapper;
import com.hmdp.service.IUserService;
import com.hmdp.utils.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    /**
     * 发送验证码接口实现方法
     *
     * @param phone 用户手机号，用于接收验证码
     * @param session HTTP会话，可用于存储用户会话信息
     *
     * 此方法首先验证手机号格式，然后生成一个6位数字的验证码，并将其存储在Redis中，
     * 最后应发送验证码到用户手机（实际发送操作在此代码中未实现，标记为TODO）
     */
    @Override
    public void sendCode(String phone, HttpSession session) {
        // 验证手机号格式
        if (!PhoneUtil.isMobile(phone)){
            throw new RuntimeException("手机号格式错误!");
        }

        // 生成6位数字的验证码
        String code = RandomUtil.randomNumbers(6);

        // 将验证码存储到Redis，有效期为1分钟
        redisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE_KEY+phone,code,1, TimeUnit.MINUTES);

        // TODO 发送短信验证码
        // 由于实际的短信发送逻辑未实现，此处记录日志作为调试信息
        log.debug("发送验证码成功:{}",code);
    }



    /**
     * 用户登录方法
     *
     * @param loginForm 登录表单数据传输对象，包含手机号、密码和验证码
     * @param session   HTTP会话，用于本次登录过程的数据存储
     *                  <p>
     *                  此方法实现用户登录功能，包括验证手机号格式、验证码校验、用户存在性检查、
     *                  新用户注册及生成登录令牌，并将用户信息保存到Redis中
     * @return
     */
    @Override
    public String login(LoginFormDTO loginForm, HttpSession session) {
        // 获取登录表单中的手机号、密码和验证码
        String phone = loginForm.getPhone();
        String password = loginForm.getPassword();
        String userCode = loginForm.getCode();

        // 验证手机号格式
        if (!PhoneUtil.isMobile(phone)){
            throw new RuntimeException("手机号格式错误!");
        }

        // 验证码校验
        String code = (String) redisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY+phone);
        if (code==null||!code.equals(userCode)){
            throw new RuntimeException("验证码错误或已过期!");
        }

        // 查询用户是否存在
        User user = query().eq("phone", phone).one();

        // 如果用户不存在，则进行注册
        if (user==null){
            user=new User();
            user.setPhone(phone);
            user.setPassword(password);
            user.setNickName(RandomUtil.randomString(6));
            save(user);
        }

        // 生成登录令牌
        String token = UUID.randomUUID().toString();
        try {
            // 将用户信息保存到Redis中，并设置过期时间
            String redisKey = RedisConstants.LOGIN_USER_KEY + token;
            UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
            Map<String, Object> userMap = BeanUtil.beanToMap(userDTO);
            redisTemplate.opsForHash().putAll(redisKey, userMap);
            redisTemplate.expire(redisKey, 30, TimeUnit.MINUTES);
        } catch (Exception e) {
            throw new RuntimeException("用户信息保存到 Redis 失败：" + e.getMessage(), e);
        }

        // 删除Redis中的验证码，避免重复使用
        redisTemplate.delete(RedisConstants.LOGIN_CODE_KEY+phone);
        //返回token
        return token;
    }
}
